<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Qt 4.3: mainwindow.cpp Example File (demos/undo/mainwindow.cpp)</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="left" valign="top" width="32"><a href="http://www.trolltech.com/products/qt"><img src="images/qt-logo.png" align="left" width="32" height="32" border="0" /></a></td>
<td width="1">&nbsp;&nbsp;</td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a>&nbsp;&middot; <a href="classes.html"><font color="#004faf">All&nbsp;Classes</font></a>&nbsp;&middot; <a href="mainclasses.html"><font color="#004faf">Main&nbsp;Classes</font></a>&nbsp;&middot; <a href="groups.html"><font color="#004faf">Grouped&nbsp;Classes</font></a>&nbsp;&middot; <a href="modules.html"><font color="#004faf">Modules</font></a>&nbsp;&middot; <a href="functions.html"><font color="#004faf">Functions</font></a></td>
<td align="right" valign="top" width="230"><a href="http://www.trolltech.com"><img src="images/trolltech-logo.png" align="right" width="203" height="32" border="0" /></a></td></tr></table><h1 align="center">mainwindow.cpp Example File<br /><sup><sup>demos/undo/mainwindow.cpp</sup></sup></h1>
<pre><span class="comment"> /****************************************************************************
 **
 ** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
 **
 ** This file is part of the documentation of the Qt Toolkit.
 **
 ** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by Trolltech ASA
** (or its successors, if any) and the KDE Free Qt Foundation. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
** you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** In addition, as a special exception, Trolltech, as the sole
** copyright holder for Qt Designer, grants users of the Qt/Eclipse
** Integration plug-in the right for the Qt/Eclipse Integration to
** link to functionality provided by Qt Designer and its related
** libraries.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
** granted herein.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ****************************************************************************/</span>

 #include &lt;QUndoGroup&gt;
 #include &lt;QUndoStack&gt;
 #include &lt;QFileDialog&gt;
 #include &lt;QMessageBox&gt;
 #include &lt;QTextStream&gt;
 #include &lt;QToolButton&gt;
 #include &quot;document.h&quot;
 #include &quot;mainwindow.h&quot;
 #include &quot;commands.h&quot;

 MainWindow::MainWindow(QWidget *parent)
     : QMainWindow(parent)
 {
     setupUi(this);

     QWidget *w = documentTabs-&gt;widget(0);
     documentTabs-&gt;removeTab(0);
     delete w;

     connect(actionOpen, SIGNAL(triggered()), this, SLOT(openDocument()));
     connect(actionClose, SIGNAL(triggered()), this, SLOT(closeDocument()));
     connect(actionNew, SIGNAL(triggered()), this, SLOT(newDocument()));
     connect(actionSave, SIGNAL(triggered()), this, SLOT(saveDocument()));
     connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
     connect(actionRed, SIGNAL(triggered()), this, SLOT(setShapeColor()));
     connect(actionGreen, SIGNAL(triggered()), this, SLOT(setShapeColor()));
     connect(actionBlue, SIGNAL(triggered()), this, SLOT(setShapeColor()));
     connect(actionAddCircle, SIGNAL(triggered()), this, SLOT(addShape()));
     connect(actionAddRectangle, SIGNAL(triggered()), this, SLOT(addShape()));
     connect(actionAddTriangle, SIGNAL(triggered()), this, SLOT(addShape()));
     connect(actionRemoveShape, SIGNAL(triggered()), this, SLOT(removeShape()));
     connect(actionAddRobot, SIGNAL(triggered()), this, SLOT(addRobot()));
     connect(actionAddSnowman, SIGNAL(triggered()), this, SLOT(addSnowman()));
     connect(actionAbout, SIGNAL(triggered()), this, SLOT(about()));
     connect(actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));

     connect(undoLimit, SIGNAL(valueChanged(int)), this, SLOT(updateActions()));
     connect(documentTabs, SIGNAL(currentChanged(int)), this, SLOT(updateActions()));

     actionOpen-&gt;setShortcut(QString(&quot;Ctrl+O&quot;));
     actionClose-&gt;setShortcut(QString(&quot;Ctrl+W&quot;));
     actionNew-&gt;setShortcut(QString(&quot;Ctrl+N&quot;));
     actionSave-&gt;setShortcut(QString(&quot;Ctrl+S&quot;));
     actionExit-&gt;setShortcut(QString(&quot;Ctrl+Q&quot;));
     actionRemoveShape-&gt;setShortcut(QString(&quot;Del&quot;));
     actionRed-&gt;setShortcut(QString(&quot;Alt+R&quot;));
     actionGreen-&gt;setShortcut(QString(&quot;Alt+G&quot;));
     actionBlue-&gt;setShortcut(QString(&quot;Alt+B&quot;));
     actionAddCircle-&gt;setShortcut(QString(&quot;Alt+C&quot;));
     actionAddRectangle-&gt;setShortcut(QString(&quot;Alt+L&quot;));
     actionAddTriangle-&gt;setShortcut(QString(&quot;Alt+T&quot;));

     m_undoGroup = new QUndoGroup(this);
     undoView-&gt;setGroup(m_undoGroup);
     undoView-&gt;setCleanIcon(QIcon(&quot;:/icons/ok.png&quot;));

     QAction *undoAction = m_undoGroup-&gt;createUndoAction(this);
     QAction *redoAction = m_undoGroup-&gt;createRedoAction(this);
     undoAction-&gt;setIcon(QIcon(&quot;:/icons/undo.png&quot;));
     redoAction-&gt;setIcon(QIcon(&quot;:/icons/redo.png&quot;));
     menuShape-&gt;insertAction(menuShape-&gt;actions().at(0), undoAction);
     menuShape-&gt;insertAction(undoAction, redoAction);

     toolBar-&gt;addAction(undoAction);
     toolBar-&gt;addAction(redoAction);

     newDocument();
     updateActions();
 };

 void MainWindow::updateActions()
 {
     Document *doc = currentDocument();
     m_undoGroup-&gt;setActiveStack(doc == 0 ? 0 : doc-&gt;undoStack());
     QString shapeName = doc == 0 ? QString() : doc-&gt;currentShapeName();

     actionAddRobot-&gt;setEnabled(doc != 0);
     actionAddSnowman-&gt;setEnabled(doc != 0);
     actionAddCircle-&gt;setEnabled(doc != 0);
     actionAddRectangle-&gt;setEnabled(doc != 0);
     actionAddTriangle-&gt;setEnabled(doc != 0);
     actionClose-&gt;setEnabled(doc != 0);
     actionSave-&gt;setEnabled(doc != 0 &amp;&amp; !doc-&gt;undoStack()-&gt;isClean());
     undoLimit-&gt;setEnabled(doc != 0 &amp;&amp; doc-&gt;undoStack()-&gt;count() == 0);

     if (shapeName.isEmpty()) {
         actionRed-&gt;setEnabled(false);
         actionGreen-&gt;setEnabled(false);
         actionBlue-&gt;setEnabled(false);
         actionRemoveShape-&gt;setEnabled(false);
     } else {
         Shape shape = doc-&gt;shape(shapeName);
         actionRed-&gt;setEnabled(shape.color() != Qt::red);
         actionGreen-&gt;setEnabled(shape.color() != Qt::green);
         actionBlue-&gt;setEnabled(shape.color() != Qt::blue);
         actionRemoveShape-&gt;setEnabled(true);
     }

     if (doc != 0) {
         int index = documentTabs-&gt;indexOf(doc);
         Q_ASSERT(index != -1);
         static const QIcon unsavedIcon(&quot;:/icons/filesave.png&quot;);
         documentTabs-&gt;setTabIcon(index, doc-&gt;undoStack()-&gt;isClean() ? QIcon() : unsavedIcon);

         if (doc-&gt;undoStack()-&gt;count() == 0)
             doc-&gt;undoStack()-&gt;setUndoLimit(undoLimit-&gt;value());
     }
 }

 void MainWindow::openDocument()
 {
     QString fileName = QFileDialog::getOpenFileName(this);
     if (fileName.isEmpty())
         return;

     QFile file(fileName);
     if (!file.open(QIODevice::ReadOnly)) {
         QMessageBox::warning(this,
                             tr(&quot;File error&quot;),
                             tr(&quot;Failed to open\n%1&quot;).arg(fileName));
         return;
     }
     QTextStream stream(&amp;file);

     Document *doc = new Document();
     if (!doc-&gt;load(stream)) {
         QMessageBox::warning(this,
                             tr(&quot;Parse error&quot;),
                             tr(&quot;Failed to parse\n%1&quot;).arg(fileName));
         delete doc;
         return;
     }

     doc-&gt;setFileName(fileName);
     addDocument(doc);
 }

 QString MainWindow::fixedWindowTitle(const Document *doc) const
 {
     QString title = doc-&gt;fileName();

     if (title.isEmpty())
         title = tr(&quot;Unnamed&quot;);
     else
         title = QFileInfo(title).fileName();

     QString result;

     for (int i = 0; ; ++i) {
         result = title;
         if (i &gt; 0)
             result += QString::number(i);

         bool unique = true;
         for (int j = 0; j &lt; documentTabs-&gt;count(); ++j) {
             const QWidget *widget = documentTabs-&gt;widget(j);
             if (widget == doc)
                 continue;
             if (result == documentTabs-&gt;tabText(j)) {
                 unique = false;
                 break;
             }
         }

         if (unique)
             break;
     }

     return result;
 }

 void MainWindow::addDocument(Document *doc)
 {
     if (documentTabs-&gt;indexOf(doc) != -1)
         return;
     m_undoGroup-&gt;addStack(doc-&gt;undoStack());
     documentTabs-&gt;addTab(doc, fixedWindowTitle(doc));
     connect(doc, SIGNAL(currentShapeChanged(QString)), this, SLOT(updateActions()));
     connect(doc-&gt;undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
     connect(doc-&gt;undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));

     setCurrentDocument(doc);
 }

 void MainWindow::setCurrentDocument(Document *doc)
 {
     documentTabs-&gt;setCurrentWidget(doc);
 }

 Document *MainWindow::currentDocument() const
 {
     return qobject_cast&lt;Document*&gt;(documentTabs-&gt;currentWidget());
 }

 void MainWindow::removeDocument(Document *doc)
 {
     int index = documentTabs-&gt;indexOf(doc);
     if (index == -1)
         return;

     documentTabs-&gt;removeTab(index);
     m_undoGroup-&gt;removeStack(doc-&gt;undoStack());
     disconnect(doc, SIGNAL(currentShapeChanged(QString)), this, SLOT(updateActions()));
     disconnect(doc-&gt;undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
     disconnect(doc-&gt;undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));

     if (documentTabs-&gt;count() == 0) {
         newDocument();
         updateActions();
     }
 }

 void MainWindow::saveDocument()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     for (;;) {
         QString fileName = doc-&gt;fileName();

         if (fileName.isEmpty())
             fileName = QFileDialog::getSaveFileName(this);
         if (fileName.isEmpty())
             break;

         QFile file(fileName);
         if (!file.open(QIODevice::WriteOnly)) {
             QMessageBox::warning(this,
                                 tr(&quot;File error&quot;),
                                 tr(&quot;Failed to open\n%1&quot;).arg(fileName));
             doc-&gt;setFileName(QString());
         } else {
             QTextStream stream(&amp;file);
             doc-&gt;save(stream);
             doc-&gt;setFileName(fileName);

             int index = documentTabs-&gt;indexOf(doc);
             Q_ASSERT(index != -1);
             documentTabs-&gt;setTabText(index, fixedWindowTitle(doc));

             break;
         }
     }
 }

 void MainWindow::closeDocument()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     if (!doc-&gt;undoStack()-&gt;isClean()) {
         int button
             = QMessageBox::warning(this,
                             tr(&quot;Unsaved changes&quot;),
                             tr(&quot;Would you like to save this document?&quot;),
                             QMessageBox::Yes, QMessageBox::No);
         if (button == QMessageBox::Yes)
             saveDocument();
     }

     removeDocument(doc);
     delete doc;
 }

 void MainWindow::newDocument()
 {
     addDocument(new Document());
 }

 static QColor randomColor()
 {
     int r = (int) (3.0*(rand()/(RAND_MAX + 1.0)));
     switch (r) {
         case 0:
             return Qt::red;
         case 1:
             return Qt::green;
         default:
             break;
     }
     return Qt::blue;
 }

 static QRect randomRect(const QSize &amp;s)
 {
     QSize min = Shape::minSize;

     int left = (int) ((0.0 + s.width() - min.width())*(rand()/(RAND_MAX + 1.0)));
     int top = (int) ((0.0 + s.height() - min.height())*(rand()/(RAND_MAX + 1.0)));
     int width = (int) ((0.0 + s.width() - left - min.width())*(rand()/(RAND_MAX + 1.0))) + min.width();
     int height = (int) ((0.0 + s.height() - top - min.height())*(rand()/(RAND_MAX + 1.0))) + min.height();

     return QRect(left, top, width, height);
 }

 void MainWindow::addShape()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     Shape::Type type;

     if (sender() == actionAddCircle)
         type = Shape::Circle;
     else if (sender() == actionAddRectangle)
         type = Shape::Rectangle;
     else if (sender() == actionAddTriangle)
         type = Shape::Triangle;
     else return;

     Shape newShape(type, randomColor(), randomRect(doc-&gt;size()));
     doc-&gt;undoStack()-&gt;push(new AddShapeCommand(doc, newShape));
 }

 void MainWindow::removeShape()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     QString shapeName = doc-&gt;currentShapeName();
     if (shapeName.isEmpty())
         return;

     doc-&gt;undoStack()-&gt;push(new RemoveShapeCommand(doc, shapeName));
 }

 void MainWindow::setShapeColor()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     QString shapeName = doc-&gt;currentShapeName();
     if (shapeName.isEmpty())
         return;

     QColor color;

     if (sender() == actionRed)
         color = Qt::red;
     else if (sender() == actionGreen)
         color = Qt::green;
     else if (sender() == actionBlue)
         color = Qt::blue;
     else
         return;

     if (color == doc-&gt;shape(shapeName).color())
         return;

     doc-&gt;undoStack()-&gt;push(new SetShapeColorCommand(doc, shapeName, color));
 }

 void MainWindow::addSnowman()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     <span class="comment">//</span> Create a macro command using beginMacro() and endMacro()

     doc-&gt;undoStack()-&gt;beginMacro(tr(&quot;Add snowman&quot;));
     doc-&gt;undoStack()-&gt;push(new AddShapeCommand(doc,
                             Shape(Shape::Circle, Qt::blue, QRect(51, 30, 97, 95))));
     doc-&gt;undoStack()-&gt;push(new AddShapeCommand(doc,
                             Shape(Shape::Circle, Qt::blue, QRect(27, 123, 150, 133))));
     doc-&gt;undoStack()-&gt;push(new AddShapeCommand(doc,
                             Shape(Shape::Circle, Qt::blue, QRect(11, 253, 188, 146))));
     doc-&gt;undoStack()-&gt;endMacro();
 }

 void MainWindow::addRobot()
 {
     Document *doc = currentDocument();
     if (doc == 0)
         return;

     <span class="comment">//</span> Compose a macro command by explicitly adding children to a parent command

     QUndoCommand *parent = new QUndoCommand(tr(&quot;Add robot&quot;));

     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(115, 15, 81, 70)), parent);
     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(82, 89, 148, 188)), parent);
     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(76, 280, 80, 165)), parent);
     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(163, 280, 80, 164)), parent);
     new AddShapeCommand(doc, Shape(Shape::Circle, Qt::blue, QRect(116, 25, 80, 50)), parent);
     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(232, 92, 80, 127)), parent);
     new AddShapeCommand(doc, Shape(Shape::Rectangle, Qt::green, QRect(2, 92, 80, 125)), parent);

     doc-&gt;undoStack()-&gt;push(parent);
 }

 void MainWindow::about()
 {
     QMessageBox::about(this, tr(&quot;About Undo&quot;), tr(&quot;The Undo demonstration shows how to use the Qt Undo framework.&quot;));
 }

 void MainWindow::aboutQt()
 {
     QMessageBox::aboutQt(this, tr(&quot;About Qt&quot;));
 }</pre>
<p /><address><hr /><div align="center">
<table width="100%" cellspacing="0" border="0"><tr class="address">
<td width="30%">Copyright &copy; 2008 <a href="trolltech.html">Trolltech</a></td>
<td width="40%" align="center"><a href="trademarks.html">Trademarks</a></td>
<td width="30%" align="right"><div align="right">Qt 4.3.5</div></td>
</tr></table></div></address></body>
</html>
